package com.black.opsoauth2.service;
import com.black.opsapi.feign.RemotePermissionService;
import com.black.opsapi.feign.RemoteRoleService;
import com.black.opsapi.feign.RemoteUserService;
import com.black.opscommon.constant.SecurityConstants;
import com.black.opscommon.entity.Permission;
import com.black.opscommon.entity.Role;
import com.black.opscommon.entity.User;
import com.black.opscommon.exception.EntityNotFoundException;
import com.black.opscommon.utils.ValidationUtil;
import com.black.opsoauth2.config.security.JwtUser;
import lombok.AllArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 〈自定义UserDetailService〉
 *
 * @author qiang.zhang
 * @date 2019/5/24
 * @since 1.0.0
 */
@Service("userDetailService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
@AllArgsConstructor
public class MyUserDetailService implements UserDetailsService {


    private final RemoteUserService remoteUserService;
    private final RemoteRoleService remoteRoleService;
    private final RemotePermissionService remotePermissionService;

    @Override
    public UserDetails loadUserByUsername(String username){

        User user;
        if(ValidationUtil.isEmail(username)){
            user = remoteUserService.findByEmail(username, SecurityConstants.FROM_IN).getData();
        } else {
            user = remoteUserService.findByUsername(username,SecurityConstants.FROM_IN).getData();
        }

        if (user == null) {
            throw new EntityNotFoundException(User.class, "name", username);
        } else {
            return create(user);
        }
    }

    public UserDetails create(User user) {
        return new JwtUser(
                user.getId(),
                user.getUsername(),
                user.getPassword(),
                user.getAvatar(),
                user.getEmail(),
                mapToGrantedAuthorities(remoteRoleService.findByUsers_Id(user.getId(),SecurityConstants.FROM_IN).getData(),remotePermissionService),
                user.getEnabled(),
                user.getCreateTime(),
                user.getLastPasswordResetTime()
        );
    }

    private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Role> roles, RemotePermissionService remotePermissionService) {

        Set<Permission> permissions = new HashSet<>();
        for (Role role : roles) {
            Set<Role> roleSet = new HashSet<>();
            roleSet.add(role);
            permissions.addAll(remotePermissionService.findByRoles_Id(role.getId(),SecurityConstants.FROM_IN).getData());
        }

        return permissions.stream()
                .map(permission -> new SimpleGrantedAuthority(permission.getName()))
                .collect(Collectors.toList());
    }

}

